import json
import re

from django.contrib.auth import authenticate
from django.middleware.csrf import get_token
from django.views import View
from django.http import JsonResponse
from django_redis import get_redis_connection
from django.contrib.auth import login
from django.contrib.auth import logout

# Create your views here.
from areas.models import Area
from celery_tasks.email.tasks import send_verify_email
from users.models import User, Address
from meiduo_mall.utils.mixins import LoginRequiredMixin
from carts.utils import CartHelper

class UsernameCountView(View):
    @staticmethod
    def get(username):
        """
        获取用户名是否已经注册
        """
        try:
            count = User.objects.filter(username=username).count()
        except Exception:
            return JsonResponse({
                'code': 400,
                'message': '操作数据库失败!'
            })

        return JsonResponse({
            'code': 0,
            'message': 'ok',
            'count': count
        })


class MobileCountView(View):
    @staticmethod
    def get(mobile):
        """
        判断手机号是否已经注册
        """
        try:
            count = User.objects.filter(mobile=mobile).count()
        except Exception:
            return JsonResponse({
                'code': 400,
                'message': '操作数据库失败!'
            })

        return JsonResponse({
            'code': 0,
            'message': 'ok',
            'count': count
        })


class RegisterView(View):
    @staticmethod
    def post(request):
        """
        注册用户
        """
        # ① 获取参数并进行校验
        req_data = json.loads(request.body.decode())
        username = req_data.get('username')
        password = req_data.get('password')
        password2 = req_data.get('password2')
        mobile = req_data.get('mobile')
        allow = req_data.get('allow')
        sms_code = req_data.get('sms_code')

        if not all([username, password, password2, mobile, allow, sms_code]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code': 400,
                                 'message': 'username格式错误'})

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({'code': 400,
                                 'message': 'password格式错误'})

        if password != password2:
            return JsonResponse({'code': 400,
                                 'message': '两次密码不一致'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                 'message': '手机号格式错误'})

        if not allow:
            return JsonResponse({'code': 400,
                                 'message': '请同意协议!'})

        redis_conn = get_redis_connection('verify_code')
        sms_code_redis = redis_conn.get(f'sms_{mobile}')

        if not sms_code_redis:
            return JsonResponse({'code': 400,
                                 'message': '短信验证码过期'})

        if sms_code != sms_code_redis:
            return JsonResponse({'code': 400,
                                 'message': '短信验证码错误'})

        try:
            user = User.objects.create_user(username=username,
                                            password=password,
                                            mobile=mobile)
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '数据库保存错误'})

        # 记录登录信息

        login(request, user)
        # ③ 返回响应
        response = JsonResponse({'code': 0,
                                'message': 'OK'})

        response.set_cookie('username',
                            user.username,
                            max_age=3600 * 24 * 14)

        cart_helper = CartHelper(request, response)
        cart_helper.merge_cookie_cart_to_redis()

        return response


# GET /csrf_token/
class CSRFTokenView(View):
    @staticmethod
    def get(request):
        """获取csrf_token的值"""
        # ① 生成csrf_token的值
        csrf_token = get_token(request)

        # ② 将csrf_token的值返回
        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'csrf_token': csrf_token})


# POST /login/
class LoginView(View):
    @staticmethod
    def post(request):
        """用户登录"""
        # ① 获取参数并进行校验(参数完整性、用户名密码是否正确)
        req_data = json.loads(request.body.decode())

        username = req_data.get('username')
        password = req_data.get('password')
        remember = req_data.get('remember')

        if not all([username, password]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})

        if re.match(r'^1[3-9]\d{9}$', username):
            User.USERNAME_FIELD = 'mobile'
        else:
            User.USERNAME_FIELD = 'username'

        # 判断用户名密码是否正确
        user = authenticate(username=username, password=password)
        if user is None:
            return JsonResponse({'code': 400,
                                 'message': '用户名或密码错误'})

        login(request, user)

        if not remember:
            request.session.set_expiry(0)

        response = JsonResponse({'code': 0,
                                 'message': 'OK'})

        # 设置 cookie 保存 username 用户名
        response.set_cookie('username',
                            user.username,
                            max_age=3600 * 24 * 14)

        cart_helper = CartHelper(request, response)
        cart_helper.merge_cookie_cart_to_redis()

        return response


# DELETE /logout/
class LogoutView(View):
    @staticmethod
    def delete(request):
        """退出登录"""
        # ① 请求登录用户的session信息
        logout(request)

        # ② 删除cookie中的username
        response = JsonResponse({'code': 0,
                                 'message': 'ok'})

        response.delete_cookie('username')

        # ③ 返回响应
        return response


class UserInfoView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        """获取登录用户个人信息"""
        user = request.user

        info = {
            'username': user.username,
            'mobile': user.mobile,
            'email': user.email,
            'email_active': user.email_active
        }

        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'user': info})


# PUT /user/email/
class UserEmailView(LoginRequiredMixin, View):
    @staticmethod
    def put(request):
        req_data = json.loads(request.body)
        email = req_data.get('email')

        if not email:
            return JsonResponse({'code': 400,
                                 'message': '缺少email参数'})

        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 400,
                                 'message': '参数email有误'})

        user = request.user
        try:
            user.email = email
            user.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '邮箱设置失败'})

        verify_url = user.generate_verify_email_url()
        send_verify_email.delay(email, verify_url)

        # ③ 返回响应
        return JsonResponse({'code': 0,
                             'message': 'OK'})


class EmailVerifyView(View):
    @staticmethod
    def put(request):
        token = request.GET.get('token')

        if not token:
            return JsonResponse({'code': 400,
                                 'message': '缺少token参数'})

        user = User.check_verify_email_token(token)

        if user is None:
            return JsonResponse({'code': 400,
                                 'message': 'token信息有误'})

        try:
            user.email_active = True
            user.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '验证邮箱失败'})

        # ③ 返回响应
        return JsonResponse({'code': 0,
                             'message': 'OK'})


class AddressView(LoginRequiredMixin, View):
    @staticmethod
    def post(request):
        """新增地址"""
        try:
            count = Address.objects.filter(user=request.user, is_delete=False).count()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '获取地址数据出错'})

        if count >= 20:
            return JsonResponse({'code': 400,
                                 'message': '收货地址超过上限'})

        # ② 接收参数并进行数据校验
        req_data = json.loads(request.body.decode())
        title = req_data.get('title')
        receiver = req_data.get('receiver')
        province_id = req_data.get('province_id')
        city_id = req_data.get('city_id')
        district_id = req_data.get('district_id')
        place = req_data.get('place')
        mobile = req_data.get('mobile')
        phone = req_data.get('phone')
        email = req_data.get('email')

        if not all([title, receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                 'message': '参数mobile有误'})

        if phone:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', phone):
                return JsonResponse({'code': 400,
                                     'message': '参数phone有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400,
                                     'message': '参数email有误'})

        try:
            address = Address.objects.create(user=request.user, **req_data)

            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '新增地址保存失败'})

        # ④ 返回响应
        address_data = {
            'id': address.id,
            'title': address.title,
            'receiver': address.receiver,
            'province': address.province.name,
            'city': address.city.name,
            'district': address.district.name,
            'place': address.place,
            'mobile': address.mobile,
            'phone': address.phone,
            'email': address.email
        }
        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'address': address_data})

    @staticmethod
    def get(request):
        """获取全部地址"""
        user = request.user
        try:
            address_list = Address.objects.filter(user_id=user.id, is_delete=False)
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '获取地址失败'})

        req_add_list = []
        for address in address_list:
            address_info = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": str(address.province),
                "city": str(address.city),
                "district": str(address.district),
                "province_id": address.province_id,
                "city_id": address.city_id,
                "district_id": address.district_id,
                "place": address.place,
                "mobile": address.mobile,
                "phone": address.phone,
                "email": address.email
            }
            req_add_list.append(address_info)

        return JsonResponse({"code": 0,
                            "message": "OK",
                            "default_address_id": user.default_address_id,
                            "addresses":req_add_list})


class AddressUpdateView(LoginRequiredMixin, View):
    @staticmethod
    def put(request, address_id):
        """编辑地址"""
        try:
            address = Address.objects.get(id=address_id, user=request.user)
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '获取地址数据出错'})

        req_data = json.loads(request.body)

        title = req_data.get('title')
        receiver = req_data.get('receiver')
        province_id = req_data.get('province_id')
        city_id = req_data.get('city_id')
        district_id = req_data.get('district_id')
        place = req_data.get('place')
        mobile = req_data.get('mobile')
        phone = req_data.get('phone')
        email = req_data.get('email')

        if not all([title, receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                 'message': '参数mobile有误'})

        if phone:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', phone):
                return JsonResponse({'code': 400,
                                     'message': '参数phone有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400,
                                     'message': '参数email有误'})

        try:
            address.title = title
            address.receiver = receiver
            address.province_id = province_id
            address.city_id = city_id
            address.district_id = district_id
            address.place = place
            address.mobile = mobile
            address.phone = phone
            address.email = email
            address.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '新增地址保存失败'})

        return JsonResponse({'code': 0,
                             'message': 'OK',
                             'address': req_data})

    @staticmethod
    def delete(request, address_id):
        """删除地址"""
        try:
            address = Address.objects.get(id=address_id, user=request.user)
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '获取地址数据出错'})

        try:
            address.is_delete = True
            address.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '删除地址出错'})

        return JsonResponse({'code': 0,
                             'message': 'OK'})


class AddressUpdateDefaultView(LoginRequiredMixin, View):
    @staticmethod
    def put(request, address_id):
        """修改默认地址"""
        user = request.user
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '获取地址数据出错'})

        try:
            user.default_address_id = address.id
            user.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '修改默认地址出错'})

        return JsonResponse({'code': 0,
                             'message': 'OK'})


class AddressUpdateTitleView(LoginRequiredMixin, View):
    @staticmethod
    def put(request, address_id):
        """修改默认地址"""
        user = request.user
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '获取地址数据出错'})

        # ② 接收参数并进行数据校验
        req_data = json.loads(request.body.decode())
        title = req_data.get('title')
        if title is None:
            return JsonResponse({'code': 400,
                                 'message': 'title信息有误'})

        try:
            address.title = title
            address.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '修改地址title出错'})

        return JsonResponse({'code': 0,
                             'message': 'OK'})


class PassWordView(LoginRequiredMixin, View):
    @staticmethod
    def put(request):
        """修改密码"""
        user = request.user

        # 接收参数并进行数据校验
        req_data = json.loads(request.body.decode())
        old_password = req_data.get('old_password')
        new_password = req_data.get('new_password')
        new_password2 = req_data.get('new_password2')

        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code': 400,
                                 'message': '缺少必传参数'})

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', old_password):
            return JsonResponse({'code': 400,
                                 'message': 'old_password格式错误'})

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', new_password):
            return JsonResponse({'code': 400,
                                 'message': 'new_password格式错误'})

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', new_password2):
            return JsonResponse({'code': 400,
                                 'message': 'new_password2格式错误'})
        # 对比旧密码是否 是登录密码
        if not user.check_password(old_password):
            return JsonResponse({'code': 400,
                                 'message': '旧密码不对'})

        if new_password != new_password2:
            return JsonResponse({'code': 400,
                                 'message': '两次密码不一致'})

        if old_password == new_password:
            return JsonResponse({'code': 400,
                                 'message': '新密码不能与旧密码一致'})
        try:
            user.set_password(new_password)
            user.save()
        except Exception:
            return JsonResponse({'code': 400,
                                 'message': '保存密码失败'})

        return JsonResponse({'code': 0,
                             'message': 'OK'})